{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "91c0b9fd-213a-4da8-b84b-c766b424716c",
   "metadata": {},
   "source": [
    "# GPT Builder Demo\n",
    "\n",
    "<a href=\"https://colab.research.google.com/github/run-llama/llama_index/blob/main/docs/examples/agent/agent_builder.ipynb\" target=\"_parent\"><img src=\"https://colab.research.google.com/assets/colab-badge.svg\" alt=\"Open In Colab\"/></a>\n",
    "\n",
    "Inspired by GPTs interface, presented at OpenAI Dev Day 2023. Construct an agent with natural language.\n",
    "\n",
    "Here you can build your own agent...with another agent!"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "3e112b8c",
   "metadata": {},
   "outputs": [],
   "source": [
    "%pip install llama-index-agent-openai\n",
    "%pip install llama-index-embeddings-openai\n",
    "%pip install llama-index-llms-openai"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "93ff34e9",
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "\n",
    "os.environ[\"OPENAI_API_KEY\"] = \"sk-...\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "0b6d7505-d582-465e-b86c-eaf2cf8c28f8",
   "metadata": {},
   "outputs": [],
   "source": [
    "from llama_index.embeddings.openai import OpenAIEmbedding\n",
    "from llama_index.llms.openai import OpenAI\n",
    "from llama_index.core import Settings\n",
    "\n",
    "Settings.llm = OpenAI(model=\"gpt-4\")\n",
    "Settings.embed_model = OpenAIEmbedding(model=\"text-embedding-3-small\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "839cb488-912e-4a34-88a4-98c751798fcc",
   "metadata": {},
   "source": [
    "## Define Candidate Tools\n",
    "\n",
    "We also define a tool retriever to retrieve candidate tools.\n",
    "\n",
    "In this setting we define tools as different Wikipedia pages."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "bc91fd57-a681-4c18-991c-6f011d180dea",
   "metadata": {},
   "outputs": [],
   "source": [
    "from llama_index.core import SimpleDirectoryReader"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "50797099-bff6-40f8-b245-62a80b07e7db",
   "metadata": {},
   "outputs": [],
   "source": [
    "wiki_titles = [\"Toronto\", \"Seattle\", \"Chicago\", \"Boston\", \"Houston\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c5aba2fc-9bde-44e7-8a69-8a25ffa8de73",
   "metadata": {},
   "outputs": [],
   "source": [
    "from pathlib import Path\n",
    "\n",
    "import requests\n",
    "\n",
    "for title in wiki_titles:\n",
    "    response = requests.get(\n",
    "        \"https://en.wikipedia.org/w/api.php\",\n",
    "        params={\n",
    "            \"action\": \"query\",\n",
    "            \"format\": \"json\",\n",
    "            \"titles\": title,\n",
    "            \"prop\": \"extracts\",\n",
    "            # 'exintro': True,\n",
    "            \"explaintext\": True,\n",
    "        },\n",
    "    ).json()\n",
    "    page = next(iter(response[\"query\"][\"pages\"].values()))\n",
    "    wiki_text = page[\"extract\"]\n",
    "\n",
    "    data_path = Path(\"data\")\n",
    "    if not data_path.exists():\n",
    "        Path.mkdir(data_path)\n",
    "\n",
    "    with open(data_path / f\"{title}.txt\", \"w\") as fp:\n",
    "        fp.write(wiki_text)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "a034ebf2-4a31-488b-bfbf-777dbc768426",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Load all wiki documents\n",
    "city_docs = {}\n",
    "for wiki_title in wiki_titles:\n",
    "    city_docs[wiki_title] = SimpleDirectoryReader(\n",
    "        input_files=[f\"data/{wiki_title}.txt\"]\n",
    "    ).load_data()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "96ccd68b-45fe-43aa-a209-b2fd5d2aa75d",
   "metadata": {},
   "source": [
    "### Build Query Tool for Each Document"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "cc9e8634-18e3-4762-8e9e-792a5ce8e934",
   "metadata": {},
   "outputs": [],
   "source": [
    "from llama_index.core import VectorStoreIndex\n",
    "from llama_index.agent.openai import OpenAIAgent\n",
    "from llama_index.core.tools import QueryEngineTool, ToolMetadata\n",
    "from llama_index.core import VectorStoreIndex\n",
    "\n",
    "# Build tool dictionary\n",
    "tool_dict = {}\n",
    "\n",
    "for wiki_title in wiki_titles:\n",
    "    # build vector index\n",
    "    vector_index = VectorStoreIndex.from_documents(\n",
    "        city_docs[wiki_title],\n",
    "    )\n",
    "    # define query engines\n",
    "    vector_query_engine = vector_index.as_query_engine(llm=llm)\n",
    "\n",
    "    # define tools\n",
    "    vector_tool = QueryEngineTool(\n",
    "        query_engine=vector_query_engine,\n",
    "        metadata=ToolMetadata(\n",
    "            name=wiki_title,\n",
    "            description=(\"Useful for questions related to\" f\" {wiki_title}\"),\n",
    "        ),\n",
    "    )\n",
    "    tool_dict[wiki_title] = vector_tool"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9d2a3aeb-11ee-4dd2-aabb-d148213e234a",
   "metadata": {},
   "source": [
    "### Define Tool Retriever"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "70d41c03-4110-4990-990b-7a3d706c0c84",
   "metadata": {},
   "outputs": [],
   "source": [
    "# define an \"object\" index and retriever over these tools\n",
    "from llama_index.core import VectorStoreIndex\n",
    "from llama_index.core.objects import ObjectIndex, SimpleToolNodeMapping\n",
    "\n",
    "tool_mapping = SimpleToolNodeMapping.from_objects(list(tool_dict.values()))\n",
    "tool_index = ObjectIndex.from_objects(\n",
    "    list(tool_dict.values()),\n",
    "    tool_mapping,\n",
    "    VectorStoreIndex,\n",
    ")\n",
    "tool_retriever = tool_index.as_retriever(similarity_top_k=1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1642f27f-457a-4cd7-b543-9f81a04a42da",
   "metadata": {},
   "source": [
    "### Load Data\n",
    "\n",
    "Here we load wikipedia pages from different cities."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "063cc9a7-d74c-4e08-9110-a63e11841d7f",
   "metadata": {},
   "source": [
    "## Define Meta-Tools for GPT Builder"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "4d76c29b-4b24-4d47-bd1e-027af9427f6c",
   "metadata": {},
   "outputs": [],
   "source": [
    "from llama_index.core.llms import ChatMessage\n",
    "from llama_index.core import ChatPromptTemplate\n",
    "from typing import List\n",
    "\n",
    "GEN_SYS_PROMPT_STR = \"\"\"\\\n",
    "Task information is given below. \n",
    "\n",
    "Given the task, please generate a system prompt for an OpenAI-powered bot to solve this task: \n",
    "{task} \\\n",
    "\"\"\"\n",
    "\n",
    "gen_sys_prompt_messages = [\n",
    "    ChatMessage(\n",
    "        role=\"system\",\n",
    "        content=\"You are helping to build a system prompt for another bot.\",\n",
    "    ),\n",
    "    ChatMessage(role=\"user\", content=GEN_SYS_PROMPT_STR),\n",
    "]\n",
    "\n",
    "GEN_SYS_PROMPT_TMPL = ChatPromptTemplate(gen_sys_prompt_messages)\n",
    "\n",
    "\n",
    "agent_cache = {}\n",
    "\n",
    "\n",
    "def create_system_prompt(task: str):\n",
    "    \"\"\"Create system prompt for another agent given an input task.\"\"\"\n",
    "    llm = OpenAI(llm=\"gpt-4\")\n",
    "    fmt_messages = GEN_SYS_PROMPT_TMPL.format_messages(task=task)\n",
    "    response = llm.chat(fmt_messages)\n",
    "    return response.message.content\n",
    "\n",
    "\n",
    "def get_tools(task: str):\n",
    "    \"\"\"Get the set of relevant tools to use given an input task.\"\"\"\n",
    "    subset_tools = tool_retriever.retrieve(task)\n",
    "    return [t.metadata.name for t in subset_tools]\n",
    "\n",
    "\n",
    "def create_agent(system_prompt: str, tool_names: List[str]):\n",
    "    \"\"\"Create an agent given a system prompt and an input set of tools.\"\"\"\n",
    "    llm = OpenAI(model=\"gpt-4\")\n",
    "    try:\n",
    "        # get the list of tools\n",
    "        input_tools = [tool_dict[tn] for tn in tool_names]\n",
    "\n",
    "        agent = OpenAIAgent.from_tools(input_tools, llm=llm, verbose=True)\n",
    "        agent_cache[\"agent\"] = agent\n",
    "        return_msg = \"Agent created successfully.\"\n",
    "    except Exception as e:\n",
    "        return_msg = f\"An error occurred when building an agent. Here is the error: {repr(e)}\"\n",
    "    return return_msg"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "02ebe043-73f1-4f09-88e1-011ceb4ed05d",
   "metadata": {},
   "outputs": [],
   "source": [
    "from llama_index.core.tools import FunctionTool\n",
    "\n",
    "system_prompt_tool = FunctionTool.from_defaults(fn=create_system_prompt)\n",
    "get_tools_tool = FunctionTool.from_defaults(fn=get_tools)\n",
    "create_agent_tool = FunctionTool.from_defaults(fn=create_agent)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c42842b3-438e-484e-9598-ad7dc7e2de09",
   "metadata": {},
   "outputs": [],
   "source": [
    "GPT_BUILDER_SYS_STR = \"\"\"\\\n",
    "You are helping to construct an agent given a user-specified task. You should generally use the tools in this order to build the agent.\n",
    "\n",
    "1) Create system prompt tool: to create the system prompt for the agent.\n",
    "2) Get tools tool: to fetch the candidate set of tools to use.\n",
    "3) Create agent tool: to create the final agent.\n",
    "\"\"\"\n",
    "\n",
    "prefix_msgs = [ChatMessage(role=\"system\", content=GPT_BUILDER_SYS_STR)]\n",
    "\n",
    "\n",
    "builder_agent = OpenAIAgent.from_tools(\n",
    "    tools=[system_prompt_tool, get_tools_tool, create_agent_tool],\n",
    "    prefix_messages=prefix_msgs,\n",
    "    verbose=True,\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "7e135c1a-fcd5-40bc-b92a-5c1ad6ad9a50",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Added user message to memory: Build an agent that can tell me about Toronto.\n",
      "=== Calling Function ===\n",
      "Calling function: create_system_prompt with args: {\n",
      "  \"task\": \"tell me about Toronto\"\n",
      "}\n",
      "Got output: System Prompt: \n",
      "\n",
      "\"Sure! I can provide you with information about Toronto. Toronto is the capital city of the province of Ontario, Canada. It is the largest city in Canada and one of the most multicultural cities in the world. Known for its diverse population, vibrant arts and culture scene, and iconic landmarks, Toronto offers a unique blend of modernity and history.\n",
      "\n",
      "Toronto is home to the CN Tower, which is one of the tallest freestanding structures in the world and offers breathtaking views of the city. The city also boasts beautiful waterfront areas, such as the Harbourfront Centre and the Toronto Islands, where visitors can enjoy recreational activities and scenic views.\n",
      "\n",
      "In terms of arts and culture, Toronto is renowned for its theaters, including the Royal Alexandra Theatre and the Princess of Wales Theatre, which host a variety of Broadway shows and musicals. The city is also home to numerous museums and galleries, such as the Art Gallery of Ontario and the Royal Ontario Museum, where visitors can explore a wide range of art and historical artifacts.\n",
      "\n",
      "Toronto is a sports-loving city, with professional sports teams in hockey, basketball, baseball, and soccer. The Toronto Maple Leafs, Toronto Raptors, Toronto Blue Jays, and Toronto FC are some of the popular teams that attract passionate fans.\n",
      "\n",
      "The city's diverse culinary scene offers a wide range of international cuisines, reflecting the multiculturalism of its residents. From fine dining restaurants to street food vendors, Toronto has something to satisfy every palate.\n",
      "\n",
      "Whether you're interested in exploring its vibrant neighborhoods, shopping in trendy boutiques, or attending exciting festivals and events, Toronto has something for everyone. Let me know if there's anything specific you'd like to know about Toronto!\"\n",
      "  \"system_prompt\": \"Sure! I can provide you with information about Toronto. Toronto is the capital city of the province of Ontario, Canada. It is the largest city in Canada and one of the most multicultural cities in the world. Known for its diverse population, vibrant arts and culture scene, and iconic landmarks, Toronto offers a unique blend of modernity and history.\\n\\nToronto is home to the CN Tower, which is one of the tallest freestanding structures in the world and offers breathtaking views of the city. The city also boasts beautiful waterfront areas, such as the Harbourfront Centre and the Toronto Islands, where visitors can enjoy recreational activities and scenic views.\\n\\nIn terms of arts and culture, Toronto is renowned for its theaters, including the Royal Alexandra Theatre and the Princess of Wales Theatre, which host a variety of Broadway shows and musicals. The city is also home to numerous museums and galleries, such as the Art Gallery of Ontario and the Royal Ontario Museum, where visitors can explore a wide range of art and historical artifacts.\\n\\nToronto is a sports-loving city, with professional sports teams in hockey, basketball, baseball, and soccer. The Toronto Maple Leafs, Toronto Raptors, Toronto Blue Jays, and Toronto FC are some of the popular teams that attract passionate fans.\\n\\nThe city's diverse culinary scene offers a wide range of international cuisines, reflecting the multiculturalism of its residents. From fine dining restaurants to street food vendors, Toronto has something to satisfy every palate.\\n\\nWhether you're interested in exploring its vibrant neighborhoods, shopping in trendy boutiques, or attending exciting festivals and events, Toronto has something for everyone. Let me know if there's anything specific you'd like to know about Toronto!\",\n",
      "  \"tool_names\": [\"Toronto\"]\n",
      "}\n",
      "Got output: Agent created successfully.\n",
      "========================\n",
      "\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "Response(response='The agent has been successfully created. It can provide detailed information about Toronto, including its history, culture, landmarks, sports teams, and culinary scene. If you have any specific questions or need more information about Toronto, feel free to ask the agent.', source_nodes=[], metadata=None)"
      ]
     },
     "execution_count": null,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "builder_agent.query(\"Build an agent that can tell me about Toronto.\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ee65b244-a6f0-447f-a88d-b7cbdfe8a74a",
   "metadata": {},
   "outputs": [],
   "source": [
    "city_agent = agent_cache[\"agent\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1c66eea2-21a9-4e3d-a3a2-f4219476903e",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Added user message to memory: Tell me about the parks in Toronto\n",
      "=== Calling Function ===\n",
      "Calling function: Toronto with args: {\n",
      "  \"input\": \"parks in Toronto\"\n",
      "}\n",
      "Got output: Toronto has a diverse array of public spaces and parks. Some of the notable ones include Nathan Phillips Square, Yonge–Dundas Square, Harbourfront Square, and Mel Lastman Square. There are also large downtown parks like Allan Gardens, Christie Pits, Grange Park, Little Norway Park, Moss Park, Queen's Park, Riverdale Park and Trinity Bellwoods Park. Other parks include Tommy Thompson Park and the Toronto Islands. The outer areas of the city have parks like High Park, Humber Bay Park, Centennial Park, Downsview Park, Guild Park and Gardens, Sunnybrook Park and Morningside Park. Toronto also operates several public golf courses. Morningside Park is the largest park managed by the city. Parts of Rouge National Urban Park, the largest urban park in North America, is also in Toronto.\n",
      "========================\n",
      "\n",
      "Toronto is known for its diverse array of public spaces and parks. Some of the notable ones include:\n",
      "\n",
      "1. **Nathan Phillips Square**: This vibrant city square features the Toronto City Hall, an ice rink, and a peace garden.\n",
      "\n",
      "2. **Yonge–Dundas Square**: Often considered Toronto's Times Square, this public square hosts many public events, performances, and art displays.\n",
      "\n",
      "3. **Harbourfront Square**: Located by the Lake Ontario, it's a key cultural district with theatres, galleries, and dining.\n",
      "\n",
      "4. **Mel Lastman Square**: Located in North York, it's a public square that hosts a variety of activities throughout the year including concerts, markets, and festivals.\n",
      "\n",
      "5. **Allan Gardens**: A park and indoor botanical garden located downtown, known for its historic, cast-iron and glass domed \"Palm House\" built in 1910.\n",
      "\n",
      "6. **High Park**: It's the largest park in downtown Toronto featuring many hiking trails, sports facilities, a beautiful lakefront, a dog park, a zoo, and playgrounds.\n",
      "\n",
      "7. **Toronto Islands**: A group of small islands located offshore from the city centre, providing shelter for the Toronto Harbour and offering stunning views of the city skyline.\n",
      "\n",
      "8. **Tommy Thompson Park**: An urban wilderness park located on the Leslie Street Spit, known for bird watching.\n",
      "\n",
      "9. **Rouge National Urban Park**: The largest urban park in North America, it's located in the city's eastern portion.\n",
      "\n",
      "10. **Morningside Park**: The largest park managed by the city, it's located in Scarborough and features picnic areas, walking trails, and a creek.\n",
      "\n",
      "These parks offer a variety of recreational activities and provide a green respite from the bustling city.\n"
     ]
    }
   ],
   "source": [
    "response = city_agent.query(\"Tell me about the parks in Toronto\")\n",
    "print(str(response))"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": ".venv",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
